import java.util.ArrayList;
import java.util.List;

import soot.SootMethod;
import soot.Unit;

public class StaticPath {
	List<StaticNode> nodes;
	List<String> called;
	int cursor;

	public StaticPath() {
		nodes = new ArrayList<StaticNode>();
		called = new ArrayList<String>();
		cursor = -1;
	}
	
	public StaticPath(StaticPath pathToCopy){
		nodes = new ArrayList<StaticNode>(pathToCopy.getNodeS());
		called = new ArrayList<String>(pathToCopy.getCalled());
		cursor = pathToCopy.getCursor();
	}

	public void setCursor(int cursor) {
		this.cursor = cursor;
	}

	public int getCursor() {
		return this.cursor;
	}

	public void addNode(StaticNode node) {
		nodes.add(node);
	}

	public List<StaticNode> getNodeS() {
		return nodes;
	}

	public void methodCalled(SootMethod method) {
		StringBuffer sb = new StringBuffer();
		sb.append(method.getDeclaringClass() + ":");
		sb.append(method.getName() + ":");
		sb.append(method.getParameterTypes().toString());
		called.add(sb.toString());
	}

	public void methodCalled(String method) {
		called.add(method);
	}

	public boolean hasBeenCalled(SootMethod method) {
		StringBuffer sb = new StringBuffer();
		sb.append(method.getDeclaringClass() + ":");
		sb.append(method.getName() + ":");
		sb.append(method.getParameterTypes().toString());

		return hasBeenCalled(sb.toString());
	}

	public boolean hasBeenCalled(String method) {
		if (called.size() == 0) {
			return false;
		}
		for (int i = 0; i < called.size(); i++) {
			if (called.get(i).equals(method)) {
				// System.out.println("is  contains|" + method);
				return true;
			}
		}
		// System.out.println("not contains|" + method);
		return false;
	}

	public int size() {
		return nodes.size();
	}

	public StaticNode getLast() {
		return nodes.get(nodes.size() - 1);
	}

	public StaticNode getNode(int index) {
		return nodes.get(index);
	}

	public boolean contains(StaticNode tempNode) {
		for (int i = 0; i < nodes.size(); i++) {
			if (nodes.get(i).getUnit().equals(tempNode.getUnit())) {
				return true;
			}
		}
		return false;
	}

	public StaticPath clone() {
		StaticPath clone = new StaticPath();
		for (int i = 0; i < this.size(); i++) {
			clone.addNode(this.getNode(i));
		}
		return clone;
	}

	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof StaticPath)) {
			return false;
		}
		StaticPath path = (StaticPath) obj;
		if (path.size() != this.size()) {
			return false;
		}
		for (int i = 0; i < path.size(); i++) {
			if (!path.getNode(i).equals(this.getNode(i))) {
				return false;
			}
		}
		return true;
	}

	public String toDebugString() {
		StringBuffer sb = new StringBuffer("");
		for (int i = 0; i < this.nodes.size(); i++) {
			sb.append(nodes.get(i).toString());
			if (nodes.get(i).isCallPoint2()) {
				sb.append(" is  call point");
			} else {
				sb.append(" not call point");
			}
			sb.append("  " + nodes.get(i).getUnit().toString() + "\n");
		}
		return sb.toString();
	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer("");
		for (int i = 0; i < this.nodes.size(); i++) {
			sb.append(nodes.get(i).toString() + "\n");
		}
		return sb.toString();
	}

	public void clearSimilar(int posX) {
		System.out.println(posX);
		for (int i = 0; i < nodes.size() - 1; i++) {
			for (int j = i + 1; j < nodes.size(); j++) {
				if (nodes.get(i).similar(nodes.get(j))) {
					// if (nodes.get(j).isCallPoint()) {
					// swap(i, j);
					// }
					nodes.remove(j);
					if (nodes.size() == 1) {
						return;
					} else {
						j--;
					}
				}
			}
		}
	}

	private void swap(int i, int j) {
		StaticNode node1 = nodes.get(i);
		StaticNode node2 = nodes.get(j);

		nodes.remove(i);
		nodes.add(i, node1);
		nodes.remove(j);
		nodes.add(i, node2);
	}

	public void clear() {
		nodes.clear();
	}

	public boolean contains(StaticPath mpath) {
		if (this.size() < mpath.size()) {
			return false;
		}
		for (int i = 0; i < this.size() - mpath.size() + 1; i++) {
			for (int j = 0; j < mpath.size(); j++) {
				if (!mpath.getNode(j).similar(this.getNode(j + i))) {
					break;
				}
				if (j == mpath.size() - 1) {
					return true;
				}
			}
		}
		return false;
	}

	public boolean contains(Unit unit) {
		for (int i = 0; i < nodes.size(); i++) {
			Unit current = nodes.get(i).getUnit();
			if (unit.toString().equals(current.toString())) {
				return true;
			}
		}
		return false;
	}

	public String nodeToString() {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < nodes.size(); i++) {
			sb.append(nodes.get(i).getUnit().toString() + "\n");
		}
		sb.append("\n");
		return sb.toString();
	}

	public boolean containsSimilar(Unit unit) {
		List tags = unit.getTags();
		for (int i = 0; i < tags.size(); i++) {
		}
		return false;
	}

	public List<String> getCalled() {
		return called;
	}

	public void setCalled(List<String> called) {
		this.called = called;
	}

	public ArrayList<String> cloneCalled() {
		ArrayList<String> clone = new ArrayList<String>();
		for (int i = 0; i < called.size(); i++) {
			clone.add(called.get(i));
		}
		return clone;
	}

	public void addNode(StaticNode node, int i) {
		nodes.add(i, node);
	}
}
